package com.bc.bcupload.common;

import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;

import com.bc.commoncore.util.ConvertUtils;
import com.bc.commoncore.util.FileUtil;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.lang.StringUtils;

public class UploadFileHelper {
    //允许的图片扩展名
    private static final Map<String, String> EXT_MAP = new HashMap<String, String>();

    static {
        EXT_MAP.put("image", ".gif,.jpg,.jpeg,.png,.bmp"); //去除所有大写,.GIF,.JPG,.JPEG,.PNG,.BMP
        EXT_MAP.put("file", ".pdf,.rar,.zip,.doc,.docx,.xls,.xlsx,.ppt,.pptx");
    }

    private static List<String> paramList = Arrays.asList("imgType", "isSize", "imgWidth",
            "imgHeight", "adType", "isThumImg", "vldSize", "platform", "module");

    private static List<String> listImgSize = null;
    private static final Lock lock = new ReentrantLock();
    private static List<String> _listImgSize;

    public static List<String> get_listImgSize() {
        if (listImgSize != null) {
            return listImgSize;
        }
        lock.lock();
        List<String> list = new ArrayList<String>();
        try {
            String filesize = PropertyUtils.getProperty("ImgSize");
            if (StringUtils.isEmpty(filesize)) {
                return null;
            }
            String[] fileArr = filesize.split(",");
            for (String item :
                    fileArr) {
                if (StringUtils.isEmpty(item)) {
                    continue;
                }
                list.add(item);
            }
            listImgSize = list;
        } catch (Exception ex) {

        } finally {
            lock.unlock();
        }
        return list;
    }

    /**
     * 上传文件
     *
     * @param request
     * @return
     * @throws Exception
     * @author hailongzhao
     * @date 20160104
     */
    public static List<ResultModel> uploadFile(HttpServletRequest request) throws Exception {
        return doUpload(request, false);
    }

    /**
     * 上传文件
     *
     * @param request
     * @return
     * @throws Exception
     * @author hailongzhao
     * @date 20160104
     */
    public static List<ResultModelPlus> uploadFilePlus(HttpServletRequest request) throws Exception {
        List<ResultModel> resultList = doUpload(request, true);
        if (resultList != null) {
            return resultList
                    .stream()
                    .map(k -> new ResultModelPlus(k.getCode(), k.getMsg(), k
                            .getDataUrl(), k.getImgName()))
                    .collect(Collectors.toList());
        }
        return new ArrayList<>();
    }

    /**
     * 根据相对路径删除对应的文件
     *
     * @param fileUrl
     * @author hailongzhao
     * @date 20160104
     */
    public static void DeleteFile(String fileUrl) {
        //fileUrl:Business/2015/10/13/13/322547f79e.jpg
        if (fileUrl == null || fileUrl.isEmpty()) {
            return;
        }
        String origPath = PropertyUtils.getProperty("FileUploadPath") + "/" + fileUrl;
        FileUtil.delete(origPath);
        FileUtil.delete(origPath + "100_100.jpg");
        FileUtil.delete(origPath + "200_200.jpg");
        FileUtil.delete(origPath + "360_360.jpg");
    }

    /**
     * 上传文件的核心逻辑
     *
     * @param request
     * @return
     * @throws Exception
     * @author hailongzhao
     * @date 20160104
     */
    @SuppressWarnings("rawtypes")
    private static List<ResultModel> doUpload(HttpServletRequest request, boolean isPlus)
            throws Exception {
        List<ResultModel> result = new ArrayList<ResultModel>();
        try {
            if (!ServletFileUpload.isMultipartContent(request)) {
                result.add(new ResultModel(-1, "请选择文件"));
                return result;
            }
            List<FileItem> fileList = new ArrayList<FileItem>();
            DiskFileItemFactory dff = new DiskFileItemFactory();
            dff.setSizeThreshold(1024000);
            ServletFileUpload sfu = new ServletFileUpload(dff);
            sfu.setHeaderEncoding("UTF-8");
            Iterator fii = sfu.parseRequest(request).iterator();
            Map<String, String> params = new HashMap<String, String>();
            while (fii.hasNext()) {
                FileItem fis = (FileItem) fii.next();
                if (fis.isFormField()) {
                    params.put(fis.getFieldName(), fis.getString("UTF-8"));
                } else {
                    if (fis.getSize() > 0) {
                        fileList.add(fis);
                    }
                }
            }
            if (fileList.size() == 0) {
                result.add(new ResultModel(-1, "请选择文件"));
                return result;
            }
            getQueryString(request, params);
            repairParamMap(params);
            //图片校验
            List<FileItem> uploadFiles = new ArrayList<FileItem>();
            for (FileItem file : fileList) {
                ResultModel resultModel = validate(file, params, isPlus);
                if (resultModel == null || resultModel.getCode() != 1) {
                    result.add(resultModel);
                    continue;
                } else {
                    uploadFiles.add(file);
                }
            }
            if (uploadFiles.size() > 0) {
                result.addAll(saveFiles(uploadFiles, params, isPlus));
            }
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            result.add(new ResultModel(-1, "上传文件失败" + e.getMessage() + getStackTrace(e)));
            return result;
        }
    }

    private static void getQueryString(HttpServletRequest request, Map<String, String> params) {
        String a = request.getQueryString();
        if (a != null && !a.trim().isEmpty()) {
            String[] pStrings = a.split("&");
            if (pStrings.length > 0) {
                for (int i = 0; i < pStrings.length; i++) {
                    if (pStrings[i] != null && !pStrings[i].trim().isEmpty()) {
                        String[] keyValues = pStrings[i].split("=");
                        if (keyValues.length == 2) {
                            if (paramList.contains(keyValues[0])) {
                                if (!params.containsKey(keyValues[0])) {
                                    params.put(keyValues[0], keyValues[1]);
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    public static String getStackTrace(Throwable ex) {
        ByteArrayOutputStream buf = new ByteArrayOutputStream();

        String e;
        try {
            ex.printStackTrace(new PrintWriter(buf, true));
            e = buf.toString();
        } catch (Exception arg10) {
            throw arg10;
        } finally {
            try {
                buf.close();
            } catch (Exception arg9) {
                ;
            }

        }

        return e;
    }

    private static void repairParamMap(Map<String, String> params) {
        String imgType = params.get("imgType");
        String isSize = params.get("isSize");
        String imgWidth = params.get("imgWidth");
        String imgHeight = params.get("imgHeight");
        String adType = params.get("adType");
        String isThumImg = params.get("isThumImg");
        //以下三个参数是v2版本的参数
        String vldSize = params.get("vldSize");
        String platform = params.get("platform");
        String module = params.get("module");
        if (imgType == null) {
            if (params.containsKey("imgType")) {
                params.remove("imgType");
            }
            params.put("imgType", "-1");
        }
        try {
            Integer.parseInt(params.get("imgType"));
        } catch (Exception e) {
            params.remove("imgType");
            params.put("imgType", "-1");
        }
        if (isSize == null) {
            if (params.containsKey("isSize")) {
                params.remove("isSize");
            }
            params.put("isSize", "");
        }
        if (imgWidth == null) {
            if (params.containsKey("imgWidth")) {
                params.remove("imgWidth");
            }
            params.put("imgWidth", "");
        }
        if (imgHeight == null) {
            if (params.containsKey("imgHeight")) {
                params.remove("imgHeight");
            }
            params.put("imgHeight", "");
        }
        if (adType == null) {
            if (params.containsKey("adType")) {
                params.remove("adType");
            }
            params.put("adType", "");
        }
        if (isThumImg == null) {
            if (params.containsKey("isThumImg")) {
                params.remove("isThumImg");
            }
            params.put("isThumImg", "");
        }
        if (vldSize == null) {
            if (params.containsKey("vldSize")) {
                params.remove("vldSize");
            }
            params.put("vldSize", "");
        }
        if (platform == null) {
            if (params.containsKey("platform")) {
                params.remove("platform");
            }
            params.put("platform", "Others");
        }
        if (module == null) {
            if (params.containsKey("module")) {
                params.remove("module");
            }
            params.put("module", "Others");
        }
    }

    /**
     * 保存文件
     *
     * @param fileItems
     * @param params
     * @return
     * @throws Exception
     */
    private static List<ResultModel> saveFiles(List<FileItem> fileItems,
                                               Map<String, String> params, boolean isPlus) throws Exception {
        List<ResultModel> result = new ArrayList<ResultModel>();
        //根据图片类型选择图片路径
        String file_type = params.get("file_type");
        if (file_type == null || file_type.equals("")) {
            throw new Exception("图片类型不能为空");
        }
        file_type = file_type.toLowerCase();
        String file_name = UUID.randomUUID().toString();
        String file_path = "/" + file_name.substring(0, 2) + "/" +
                file_name.substring(2, 4) + "/" + file_name + "/";
        //文件上传后的保存目录路径
        String fileUploadPath = PropertyUtils.getProperty("FileUploadPath");
        //图片服务器域名
        String serverUrl = PropertyUtils.getProperty("WebApiAddress");

        //上传到服务器的路径
        String filePath = fileUploadPath + "/" + file_type + file_path; //String.format("/%d/%d/%d", year, month, day);
        //不存在路径则创建
        FileUtil.createDirectory(filePath);
        //循环文件验证及保存
        for (FileItem file : fileItems) {
            ResultModel resultModel = null;
            try {
                String fileExtension = file.getName().substring(file.getName().lastIndexOf(".")).toLowerCase();
                String saveName = file_name + fileExtension;
                if (EXT_MAP.get("image").contains(fileExtension)) {
                    //如果是图片地址是_orig
                    saveName = file_name + "_orig" + fileExtension;
                }
                //如果是文件
                String origPath = filePath + "/" + saveName;
                File uploadedFile = new File(origPath);
                file.write(uploadedFile);
                //生成缩略图
                String newFilePath = origPath.replace("_orig", "");
                //新原图地址
                String newOrig = newFilePath.substring(0, newFilePath.lastIndexOf(".")) + ".jpg";
                String dataUrl = serverUrl + "/" + file_type + file_path + file_name + fileExtension;
                if (EXT_MAP.get("image").contains(fileExtension)) {
                    //生成原图开始
                    File picture = new File(origPath);
                    BufferedImage sourceImg = ImageIO.read(new FileInputStream(picture));
                    int width = sourceImg.getWidth();
                    int height = sourceImg.getHeight();
                    ImageCuter.cut(origPath, newOrig, width, height);
                    //生成原图结束
                    for (String item : get_listImgSize()) {
                        int w = ConvertUtils.objectToInt(item.split("_")[0]);
                        int h = ConvertUtils.objectToInt(item.split("_")[1]);
                        ImageCuter.cut(origPath, newOrig + "_" + item + ".jpg", w, h);
                    }
                    dataUrl = serverUrl + "/" + file_type + file_path + "/" + file_name + ".jpg";
                }
                resultModel = new ResultModel(1, "上传成功", dataUrl,
                        file.getName().replace("\"", ""));
            } catch (Exception e) {
                e.printStackTrace();
                resultModel = new ResultModel(4, "上传文件失败");
            }
            result.add(resultModel);
        }
        return result;
    }

    /**
     * 文件验证
     *
     * @param file
     * @param params
     * @return
     */
    private static ResultModel validate(FileItem file, Map<String, String> params, boolean isPlus) {
        //判断文件大小是否有效
        String fileMaxSize = PropertyUtils.getProperty("FileMaxSize");
        if (file.getSize() > Long.parseLong(fileMaxSize)) {
            return new ResultModel(-2, "文件大小超过限制");
        }
        //文件扩展名验证
        if (file.getName().lastIndexOf(".") <= 0) {
            return new ResultModel(3, "文件格式不正确");
        }
        String fileExtension = file.getName().substring(file.getName().lastIndexOf(".")).toLowerCase();
        if (!EXT_MAP.get("image").contains(fileExtension)
                && !EXT_MAP.get("file").contains(fileExtension)) {
            return new ResultModel(3, "文件格式不正确");
        }

        //仅图片进行尺寸验证
        try {
            if (EXT_MAP.get("image").contains(fileExtension)) {
                BufferedImage img = ImageCuter.getBufferedImage(file.getInputStream());
                String checkSize = "";
                String imgWidth = params.get("imgWidth");
                String imgHeight = params.get("imgHeight");
                if (isPlus) {
                    checkSize = params.get("vldSize");
                } else {
                    checkSize = params.get("isSize");
                    ResultModel temp = validateAD(file, params, img);
                    if (temp != null) {
                        return temp;
                    }
                }
                //根据isSize、imgWidth、imgHeight参数判断是否尺寸验证
                if ("1".equals(checkSize)) {
                    //图片尺寸验证
                    if (!(img.getWidth() + "").equals(imgWidth) || !(img.getHeight() + "").equals(imgHeight)) {
                        return new ResultModel(2, "图片不符合规定尺寸");
                    }
                }
            }

        } catch (Exception ex) {
            return new ResultModel(6, "图片解析失败" + ex.getMessage());
        }
        return new ResultModel(1, "验证通过");
    }

    private static ResultModel validateAD(FileItem file, Map<String, String> params, BufferedImage img) {
        String imgTypeParam = params.get("imgType");
        String adType = params.get("adType");
        int imgType = 0;
        try {
            imgType = Integer.parseInt(imgTypeParam);
        } catch (Exception e) {
            //: handle exception
        }
        if (imgType >= 1 && imgType <= 7) {
            AdType at = AdType.getEnum(adType);
            if (at != null) {
                if (at.getValue().equals("0")) {
                    return new ResultModel(2, "请先选择广告位再上传对应图片");
                } else {
                    if (img.getWidth() != at.getWidth()
                            || img.getHeight() != at.getHeight()) {
                        return new ResultModel(2, "图片不符合规定尺寸");
                    }
                    if (at.getValue().equals(AdType.A.getValue())) {
                        String adMaxSize4A = PropertyUtils.getProperty("ADMaxSize4A");
                        long size = Long.parseLong(adMaxSize4A);
                        if (file.getSize() > size) {
                            return new ResultModel(2, ("A区广告大小超过限制" + (size / 1024) + "K"));
                        }
                    }
                }
            }
        }
        return null;
    }

}
